#include "ShaderParameter.h"
#include "Renderer.h"

using namespace Nezha;

_RawBuffer::_RawBuffer(u16 sizeInBytes)
	:mData(NULL)
	,mSizeInBytes(0)
{
	resize(sizeInBytes);
}

_RawBuffer::_RawBuffer()
	:mData(NULL)
	,mSizeInBytes(0)
{

}

_RawBuffer::_RawBuffer(const _RawBuffer& rb)
	:mData(NULL)
	,mSizeInBytes(0)
{
	*this = rb;
}

_RawBuffer::~_RawBuffer()
{
	resize(0);
}

void _RawBuffer::resize(u16 sizeInBytes)
{
	if(mSizeInBytes != sizeInBytes)
	{
		if(mData)
		{
			NZFree(mData);
		}

		if(sizeInBytes > 0)
		{
			mData = (u8*)NZMalloc(sizeInBytes);
			memset(mData, 0, sizeInBytes);
			mSizeInBytes = sizeInBytes;
		}
		else
		{
			mData = NULL;
			sizeInBytes = 0;
		}
	}
}

_RawBuffer& _RawBuffer::operator = (const _RawBuffer& rb)
{
	resize(rb.mSizeInBytes);

	if(mData)
	{
		memcpy(mData, rb.mData, mSizeInBytes);
	}

	return *this;
}
u32 ShaderParameter::DataTypeSize(ShaderParamDataType spdt)
{
	switch(spdt)
	{
		// FIXME for fixed
	case SPDT_FIXED:
		break;
	case SPDT_FIXED2:
		break;
	case SPDT_FIXED3:
		break;
	case SPDT_FIXED2X3:
		break;
	case SPDT_FIXED3X3:
		break;
	case SPDT_FIXED4X3:
		break;
	case SPDT_FIXED4:
		break;
	case SPDT_FIXED2X4:
		break;
	case SPDT_FIXED3X4:
		break;
	case SPDT_FIXED4X4:
		break;
	case SPDT_HALF:
		return sizeof(u16);
	case SPDT_HALF2:
		return sizeof(u16) * 2;
	case SPDT_HALF3:
		return sizeof(u16) * 3;
	case SPDT_HALF2X3:
		return sizeof(u16) * 6;
	case SPDT_HALF3X3:
		return sizeof(u16) * 9;
	case SPDT_HALF4X3:
		return sizeof(u16) * 12;
	case SPDT_HALF4:
		return sizeof(u16) * 4;
	case SPDT_HALF2X4:
		return sizeof(u16) * 8;
	case SPDT_HALF3X4:
		return sizeof(u16) * 12;
	case SPDT_HALF4X4:
		return sizeof(u16) * 16;
	case SPDT_INT:
		return sizeof(int);
	case SPDT_INT2:
		return sizeof(int) * 2;
	case SPDT_INT3:
		return sizeof(int) * 3;
	case SPDT_INT2X3:
		return sizeof(int) * 6;
	case SPDT_INT3X3:
		return sizeof(int) * 9;
	case SPDT_INT4X3:
		return sizeof(int) * 12;
	case SPDT_INT4:
		return sizeof(int) * 4;
	case SPDT_INT2X4:
		return sizeof(int) * 8;
	case SPDT_INT3X4:
		return sizeof(int) * 12;
	case SPDT_INT4X4:
		return sizeof(int) * 16;
	case SPDT_FLOAT:
		return sizeof(float);
	case SPDT_FLOAT2:
		return sizeof(float) * 2;
	case SPDT_FLOAT3:
		return sizeof(float) * 3;
	case SPDT_FLOAT2X3:
		return sizeof(float) * 6;
	case SPDT_FLOAT3X3:
		return sizeof(float) * 9;
	case SPDT_FLOAT4X3:
		return sizeof(float) * 12;
	case SPDT_FLOAT4:
		return sizeof(float) * 4;
	case SPDT_FLOAT2X4:
		return sizeof(float) * 8;
	case SPDT_FLOAT3X4:
		return sizeof(float) * 12;
	case SPDT_FLOAT4X4:
		return sizeof(float) * 16;
	case SPDT_USER:
		break;
	}

	return 0;
}


void ShaderParameter::create(const ShaderParamDesc& desc)
{
	// already created.
	if(isValid())
		return;

	NZ_ASSERT(getCategory() == desc.Category);

	mDataType = desc.DataType;
	mName = desc.Name;
	mBuffer.resize(DataTypeSize(mDataType));
	mHandle = desc.ImplHandle;
}


_SamplerInfo::_SamplerInfo()
	:mBorderColor(0xFF000000)
	,mMinFilter(ShaderSampler::LINEAR)
	,mMagFilter(ShaderSampler::LINEAR)
	,mLodBias(0)
	,mSamplerType(SAMPLER_EMPTY)
	,mTextureID(0)
	,mWrapU(ShaderSampler::WM_CLAMP)
	,mWrapV(ShaderSampler::WM_CLAMP)
	,mWrapW(ShaderSampler::WM_CLAMP)
	,mAnisotropic(1.0f)
{

}

ShaderSampler::ShaderSampler()
{
	memset(&mInfo, 0, sizeof(mInfo));
}

ShaderSampler::~ShaderSampler()
{
	mTexturePtr.release();
}

void ShaderSampler::_setSamplerInfo(const _SamplerInfo& si)
{
	mInfo = si;

	TextureManager* tm = Renderer::GetGlobal()->getTextureManager();
	mTexturePtr = tm->getTexture(si.mTextureID);
}